package jnpf.database.util;

import com.baomidou.mybatisplus.annotation.DbType;
import jnpf.database.model.dto.DataSourceDTO;
import jnpf.database.model.interfaces.DataSourceMod;
import jnpf.exception.DataException;
import jnpf.database.source.DbBase;
import jnpf.database.source.impl.*;
import jnpf.util.StringUtil;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * 获取数据库类型及相关信息类
 *
 * @author JNPF开发平台组
 * @version V3.2.0
 * @copyright 引迈信息技术有限公司
 * @date 2021/10/6
 */
public class DbTypeUtil {


    /**
     * 出现编码不符合规范的地方
     */
    public static final String CONFIG = "项目配置中";
    public static final String LINK = "数据连接中";
    public static final String URL = "URL中";

    /*===========================数据库对象（重载）=====================================*/

    /**
     * 根据数据库名获取数据库对象
     * Case insensitive 大小写不敏感
     * @param dbSourceOrDbLink 数据源
     * @return  DbTableEnum2 数据表枚举类
     */
    public static DbBase getDb(DataSourceMod dbSourceOrDbLink) throws DataException {
        String dbSourceOrDbLinkEncode = getEncode(dbSourceOrDbLink.dataSourceDTO());
        return getDbCommon(dbSourceOrDbLinkEncode);
    }

    public static DbBase getDb(Connection conn) {
        try {
            return getDb(conn.getMetaData().getURL());
        } catch (SQLException | DataException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static DbBase getDb(String url) throws DataException {
        String dbType = url.split(":")[1];
        for(DbBase dbBase : DbBase.DB_BASES){
            if(dbType.equals(dbBase.getConnUrlEncode())){
                return dbBase;
            }
        }
        throw new DataException("通过url找不到对应数据库");
    }

    /**==========================获取URL(重载)===============================**/
    public static String getUrl(DataSourceMod dbSourceOrDbLink){
        return getUrl(dbSourceOrDbLink, null);
    }

    /**
     * 指定库名（多租户）
     * @param dbSourceOrDbLink 数据源
     * @param dbName 数据库名
     * @return url连接
     */
    public static String getUrl(DataSourceMod dbSourceOrDbLink, String dbName){
        DataSourceDTO dsd = dbSourceOrDbLink.dataSourceDTO();
        try {
            if(StringUtil.isNotEmpty(dbName)) {
                dsd.setDbName(dbName);
            }
            return getDb(dbSourceOrDbLink).getConnUrl(dsd.getPrepareUrl(),dsd.getHost(),dsd.getPort(),dsd.getDbName());
        } catch (DataException e) {
            e.printStackTrace();
        }
        return null;
    }
    /*===========================校验数据库类型=============================*/
    /**
     * IOC思想
     * @return 是否匹配
     */
    private static Boolean checkDb(DataSourceMod dataSourceMod, String encode){
        DataSourceDTO dataSourceDTO = dataSourceMod.dataSourceDTO();
        String dataSourDbEncode = null;
        try {
            dataSourDbEncode = getEncode(dataSourceDTO);
        } catch (DataException e) {
            e.printStackTrace();
        }
        return encode.equals(dataSourDbEncode);
    }


    public static Boolean checkOracle(DataSourceMod dataSourceMod){
        return checkDb(dataSourceMod, DbOracle.DB_ENCODE);
    }
    public static Boolean checkMySQL(DataSourceMod dataSourceMod){
        return checkDb(dataSourceMod, DbMySQL.DB_ENCODE);
    }
    public static Boolean checkSQLServer(DataSourceMod dataSourceMod){
        return checkDb(dataSourceMod, DbSQLServer.DB_ENCODE);
    }
    public static Boolean checkDM(DataSourceMod dataSourceMod){
        return checkDb(dataSourceMod, DbDM.DB_ENCODE);
    }
    public static Boolean checkKingbase(DataSourceMod dataSourceMod){
        return checkDb(dataSourceMod, DbKingbase.DB_ENCODE);
    }
    public static Boolean checkPostgre(DataSourceMod dataSourceMod){
        return checkDb(dataSourceMod,DbPostgre.DB_ENCODE);
    }

    /*============================专用代码区域=========================*/

    /**
     * MybatisPlusConfig
     */
    public static <T extends DataSourceUtil>DbType getMybatisEnum(T dataSourceUtil) throws DataException{
        return getDb(dataSourceUtil).getMpDbType();
    }

    /**
     * 默认数据库与数据连接判断
     */
    public static Boolean compare(String dbType1,String dbType2) throws DataException{
        dbType1 = checkDbTypeExist(dbType1,null,false);
        dbType2 = checkDbTypeExist(dbType2,null,false);
        if(dbType1 != null && dbType2 != null){
            return dbType1.equals(dbType2);
        }else {
            return false;
        }
    }

    /*=========================内部复用代码================================*/

    /*====标准类型（重载）==*/

    /**
     * 获取标准类型编码
     * 根据DbType
     * @param dataSourceDTO 数据源
     * @return String
     */
    private static String getEncode(DataSourceDTO dataSourceDTO)throws DataException{
        String ExceptionResource;
        if(dataSourceDTO.getDataSourceFrom() == 1){
            ExceptionResource = LINK;
        }else {
            ExceptionResource = CONFIG;
        }
        return checkDbTypeExist(dataSourceDTO.getDbType(), ExceptionResource,true);
    }
    /**============**

     /**
     * 获取数据库对象
     * @param encode 数据标准编码
     * @return 数据库基类
     */
    private static DbBase getDbCommon(String encode){
        for (DbBase db : DbBase.DB_BASES) {
            if (db.getDbEncode().equalsIgnoreCase(encode)) {
                return db;
            }
        }
        return null;
    }

    /**
     * 0、校验数据类型是否符合编码标准（包含即可）
     * @param dbType 数据类型
     * @param dbTypeSourceInfo 数据编码来源信息
     * @return 数据标准编码
     * @throws DataException 数据库类型不符合编码
     */
    private static String checkDbTypeExist(String dbType, String dbTypeSourceInfo, Boolean exceptionOnOff) throws DataException {
        for(String enEncode : DbBase.DB_ENCODES){
            if(enEncode.equals(dbType)){
                return enEncode;
            }
        }
        if(exceptionOnOff){
            throw DataException.DbTypeCompare(dbTypeSourceInfo);
        }
        return null;
    }





}
